package com.asen.libcommon.http.livedata

import androidx.lifecycle.LiveData
import retrofit2.*
import retrofit2.CallAdapter.Factory
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.concurrent.atomic.AtomicBoolean


/**
 * @date   : 2021/3/1
 * @author : asenLiang
 * @e-mail : liangAisiSen@163.com
 * @desc   : LiveData<LiveDataResponse<T>> 格式返回封装工厂适配器
 */
class LiveDataCallAdapterFactory : Factory() {
    override fun get(
        returnType: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): CallAdapter<*, *>? {
        if (getRawType(returnType) != LiveData::class.java) {
            return null
        }
        val observableType = getParameterUpperBound(0, returnType as ParameterizedType)
        val rawObservableType = getRawType(observableType)
        if (rawObservableType != LiveDataResponse::class.java) {
            throw IllegalArgumentException("type must be a resource")
        }
        if (observableType !is ParameterizedType) {
            throw IllegalArgumentException("resource must be parameterized")
        }
        val bodyType = getParameterUpperBound(0, observableType)
        return LiveDataCallAdapter<Any>(bodyType)
    }


    class LiveDataCallAdapter<R>(private val responseType: Type) : CallAdapter<R, LiveData<LiveDataResponse<R>>> {

        override fun responseType() = responseType

        override fun adapt(call: Call<R>): LiveData<LiveDataResponse<R>> {
            return object : LiveData<LiveDataResponse<R>>() {
                private var started = AtomicBoolean(false)
                override fun onActive() {
                    super.onActive()
                    if (started.compareAndSet(false, true)) {
                        call.enqueue(object : Callback<R> {
                            override fun onResponse(call: Call<R>, response: Response<R>) {
                                postValue(LiveDataResponse.create(response))
                            }

                            override fun onFailure(call: Call<R>, throwable: Throwable) {
                                postValue(LiveDataResponse.create(throwable))
                            }
                        })
                    }
                }
            }
        }
    }
}